/**
 * create by zhang_tian_xiao, 2018/5/21 18:58
 *
 * */
package com.ax.framework.jfinal.db.dialect

import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONArray
import com.alibaba.fastjson.JSONObject
import com.ax.asInstanceOf
import com.ax.getTypeOfArray
import com.ax.toHump
import com.jfinal.plugin.activerecord.*
import com.jfinal.plugin.activerecord.builder.TimestampProcessedModelBuilder
import com.jfinal.plugin.activerecord.builder.TimestampProcessedRecordBuilder
import com.jfinal.plugin.activerecord.dialect.PostgreSqlDialect
import org.postgresql.util.PGobject
import java.sql.*
import java.sql.Date
import java.util.*

object PostgreSqlDialect : PostgreSqlDialect() {

    init {
        this.setModelBuilder(object : TimestampProcessedModelBuilder() {
            override fun <T : Any?> build(rs: ResultSet, modelClass: Class<out Model<*>>): MutableList<T> {
                val result = mutableListOf<T>()
                val rsmd = rs.getMetaData()
                val columnCount = rsmd.columnCount
                val labelNames = arrayOfNulls<String>(columnCount + 1)
                val types = IntArray(columnCount + 1)
                this.buildLabelNamesAndTypes(rsmd, labelNames, types)

                while (rs.next()) {
                    val ar = modelClass.newInstance()
                    val attrs = CPI.getAttrs(ar)

                    for (i in 1..columnCount) {
                        val column_name = labelNames[i]
                        val value: Any?
                        if (types[i] < 91) {
                            value = rs.getObject(i)
                        } else if (types[i] == 93) {
                            value = rs.getTimestamp(i)
                        } else if (types[i] == 91) {
                            value = rs.getDate(i)
                        } else if (types[i] == 2005) {
                            value = this.handleClob(rs.getClob(i))
                        } else if (types[i] == 2011) {
                            value = this.handleClob(rs.getNClob(i))
                        } else if (types[i] == 2004) {
                            value = this.handleBlob(rs.getBlob(i))
                        } else if (types[i] == Types.ARRAY) {
                            val array = rs.getArray(i).array
                            //返回值名称
                            val return_name = cn.hutool.core.util.ReflectUtil.getMethod(modelClass, "get" + column_name?.toHump(true)).returnType.simpleName
                            if (return_name == "JSONArray") {
                                value = JSON.parseArray(JSON.toJSONString(array))
                            }
                            //Java原生类型数组
                            else {
                                value = array as Array<*>
                            }
                        } else if (types[i] == 1111) {
                            value = JSON.parseObject(rs.getObject(i).asInstanceOf<PGobject>().value)
                        } else {
                            value = rs.getObject(i)
                        }

                        attrs[column_name] = value
                    }
                    result.add(ar as T)
                }

                return result
            }
        }).setRecordBuilder(object : TimestampProcessedRecordBuilder() {
            override fun build(config: Config, rs: ResultSet): MutableList<Record> {
                val result = ArrayList<Record>()
                val rsmd = rs.getMetaData()
                val columnCount = rsmd.columnCount
                val labelNames = arrayOfNulls<String>(columnCount + 1)
                val types = IntArray(columnCount + 1)
                this.buildLabelNamesAndTypes(rsmd, labelNames, types)

                while (rs.next()) {
                    val record = Record()
                    CPI.setColumnsMap(record, config.getContainerFactory().columnsMap as Map<String, Object>)
                    val columns = record.columns

                    for (i in 1..columnCount) {
                        var value: Any?
                        if (types[i] < 91) {
                            value = rs.getObject(i)
                        } else if (types[i] == 93) {
                            value = rs.getTimestamp(i)
                        } else if (types[i] == 91) {
                            value = rs.getDate(i)
                        } else if (types[i] == 2005) {
                            value = ModelBuilder.me.handleClob(rs.getClob(i))
                        } else if (types[i] == 2011) {
                            value = ModelBuilder.me.handleClob(rs.getNClob(i))
                        } else if (types[i] == 2004) {
                            value = ModelBuilder.me.handleBlob(rs.getBlob(i))
                        } else if (types[i] == 2003) {
                            //Record就尴尬了. 拿不到返回值类型, 只能转成JSONArray方便操作
                            val array = rs.getArray(i).array::class.java.typeName
                            //如果pg驱动默认给转成了字符串, 或者本身就是字符串数组, 统一转换成JSONArray
                            if (array::class.java.simpleName == "String[]") {
                                value = JSON.parseArray(JSON.toJSONString(array))
                            } else {
                                value = rs.getArray(i).array as Array<*>
                            }
                        } else if (types[i] == 1111) {
                            try {
                                value = JSON.parseObject(rs.getObject(i).asInstanceOf<PGobject>().value)
                            } catch (e: Exception) {
                                value = rs.getObject(i)
                            }
                        } else {
                            value = rs.getObject(i)
                        }
                        columns[labelNames[i]] = value
                    }

                    result.add(record)
                }
                return result
            }
        })
    }

    private fun getValue(type: Int, i: Int, rs: ResultSet) {
        var value: Any?
        if (type < 91) {
            value = rs.getObject(i)
        } else if (type == 93) {
            value = rs.getTimestamp(i)
        } else if (type == 91) {
            value = rs.getDate(i)
        } else if (type == 2005) {
            value = ModelBuilder.me.handleClob(rs.getClob(i))
        } else if (type == 2011) {
            value = ModelBuilder.me.handleClob(rs.getNClob(i))
        } else if (type == 2004) {
            value = ModelBuilder.me.handleBlob(rs.getBlob(i))
        } else if (type == 2003) {
            value = rs.getArray(i).array as Array<*>
        } else if (type == 1111) {
            try {
                value = JSON.parseObject(rs.getObject(i).asInstanceOf<PGobject>().value)
            } catch (e: Exception) {
                value = rs.getObject(i)
            }
        } else {
            value = rs.getObject(i)
        }
    }

    @Throws(SQLException::class)
    override fun fillStatement(pst: PreparedStatement, paras: List<Any>) {
        var i = 0
        val size = paras.size
        while (i < size) {
            i = i(paras, i, pst)
        }
    }

    @Throws(SQLException::class)
    override fun fillStatement(pst: PreparedStatement, vararg paras: Any) {
        var i = 0
        val size = paras.size
        val list = paras.toList()
        while (i < size) {
            i = i(list, i, pst)
        }
    }


    private fun i(paras: List<Any>, i: Int, pst: PreparedStatement): Int {
        var i1 = i
        val value = paras[i1]
        if (value is Date) {
            pst.setDate(i1 + 1, value)
        } else if (value is Timestamp) {
            pst.setTimestamp(i1 + 1, value)
        } else if (value is java.util.Date) {
            pst.setTimestamp(i1 + 1, Timestamp(value.time))
        } else if (value is Array<*>) {
            //获取到当前数组的类型
            val array_type = value.getTypeOfArray()
            //获取到对应的Pg类型
            val pg_type = javaTypeToPsqlType(array_type)
            //创建对应类型的pg_array对象
            pst.setArray(i1 + 1, pst.connection.createArrayOf(pg_type, value))
        } else if (value is JSONObject) {
            //
            val pg_object = PGobject()
            pg_object.type = "jsonb"
            pg_object.value = value.asInstanceOf<JSONObject>().toJSONString()
            pst.setObject(i1 + 1, pg_object)
        } else if (value is JSONArray) {
            //
            val array = value.asInstanceOf<JSONArray>().toJavaList(String::class.java).toTypedArray()
            pst.setArray(i1 + 1, pst.connection.createArrayOf("jsonb", array))
        } else {
            //
            pst.setObject(i1 + 1, value)
        }
        i1++
        return i1
    }

    private fun javaTypeToPsqlType(type: String): String {
        when (type) {
            "String" -> return "text"
            "Integer" -> return "int"
            "Long" -> return "bigint"
        }
        return "";
    }
}

fun main(args: Array<String>) {
    println("abc".drop(1))
    println("abc".dropLast(1))
}